/******************************************************************************
Copyright:
2009 Jens Collin (jens.collin@dinomin.com)

This file is part of Envox Decompiler.

Envox Decompiler is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

Envox Decompiler is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with KitchenOS.  If not, see <http://www.gnu.org/licenses/>.

******************************************************************************/
using System;
using System.Collections;

namespace EnvoxDecompiler
{
	/// <summary>
	/// Summary description for Block_DBSQL.
	/// </summary>
	public class Block_DBSQL : Block
	{

		private string _storeNoRecordsInto;
		private string _database;
		private string _sqlCommand;

		private long _noParameters;

		private ArrayList parameters = new ArrayList();


		public override TYPE GetBlockType()
		{
			return TYPE.DBSQL;
		}

		public override string GetXML(int x, int y)
		{
			Trace.Debug("Block_DBSQL::GetXML Started.");	
			// <DbSQL name="NAME" rect="X 32 96 56"
            string xml = "\t\t\t<DbSQL name=\"" + Utils.XmlString(_name) + "\" rect=\"" + x + " " + y + " 96 56\"";
			//  ...description="DESC"...
			xml += GetDescriptionXML();
			//  ...clearDTMF="_clearDTMFBuffer"...
			xml += GetClearDTMFXML();
			// ...minUserLevel="_userLevel"
			xml += GetMinUserLevelXML();
			// ...cpMessage=""...
			xml += GetControlPanelMessageXML();

			// ...database="DB"...
			xml += " database=\"" + Utils.XmlString(_database) + "\"";
			// ...query="SQL_QUERY"...
			xml += " query=\"" + Utils.XmlString(_sqlCommand) + "\"";
			// ...affectedRowsVar="STORE_NUM_REC_INTO"...
			xml += " affectedRowsVar=\"" + Utils.XmlString(_storeNoRecordsInto) + "\"";
			// ...queryData=""...
			// TODO: Why is this blank. When will it be anything?
			xml += " queryData=\"" + Utils.XmlString("") + "\"";

			// End the header xml-part.
			xml += ">\r\n";

			// <Inputs>
			xml += GetInputsXML(_blockId);
		
			// <Outputs>
			xml += GetOutputsXML();

			// <Logs>
			xml += GetLogsXML();
			
			xml += GetHandledErrorsXML();

			// <Parameters>
			xml +="\t\t\t\t<Parameters>\r\n";
			foreach (DbParameter dbp in parameters)
			{
				xml += "\t\t\t\t\t" + dbp.GetXML() + "\r\n";
			}
			xml +="\t\t\t\t</Parameters>\r\n";

			// </DbSQL>
			xml +="\t\t\t</DbSQL>\r\n";
			return xml;
		}


		private bool CreateParameter(byte[] data)
		{
			Trace.Debug("CreateParameter start");

			long step = 12;
			bool hasInput = data[4] != 0x00;
			bool hasOutput = data[8] != 0x00;

			string inputName = null;
			string outputName = null;

			if (hasInput)
			{
				inputName = Utils.DataToString(data, step);
				step = step + Utils.DataStringLength(data, step);
			}

			if (hasOutput)
			{
				outputName = Utils.DataToString(data, step);
				step = step + Utils.DataStringLength(data, step);
			}

			try
			{
				DbParameter parameter = new DbParameter(inputName, outputName);
				parameters.Add(parameter);
				parameter.Dump();
			}
			catch (UnimplementedException ue)
			{
				Trace.Debug(ue);
				AddToBlockNote("A DBParameter could not be reversed, please check block parameters.");
			}

			return true;
		}


		private bool ReadParameters()
		{
			Trace.Debug("ReadParameters start");
			// Read parameters
			for (int i=1; i <= _noParameters; i++)
			{
				long fieldLength = _rawData[_currentPos] + _rawData[_currentPos + 1] * 256;
				// Create a smaller block with data in it
				byte[] _subData = new byte[fieldLength];
				for (long inner=0; inner < fieldLength; inner++)
				{
					_subData[inner] = _rawData[_currentPos+inner];
				}
				// Jump forwards.
				_currentPos += fieldLength;
				
				CreateParameter(_subData);
			}
			return true;
		}


		public Block_DBSQL(byte[] rawData) : base(rawData)
		{
			Trace.Debug("Block_DBSQL created.");

			outputErrorIds.Add(new BlockOutput(OUTPUT.Next, 0));
			outputErrorIds.Add(new BlockOutput(OUTPUT.DbFailed, 37));
			outputErrorIds.Add(new BlockOutput(OUTPUT.DbSQLExpr, 52));
			outputErrorIds.Add(new BlockOutput(OUTPUT.DbTimeout, 34));
			outputErrorIds.Add(new BlockOutput(OUTPUT.DbLocked, 32));
			outputErrorIds.Add(new BlockOutput(OUTPUT.DbAuthorize, 33));
			outputErrorIds.Add(new BlockOutput(OUTPUT.ConnectFailed, 31));
			outputErrorIds.Add(new BlockOutput(OUTPUT.SQLFailed, 168));

			_noParameters = _rawData[_currentPos + 16] + _rawData[_currentPos + 17] * 256;

			_currentPos += 20;

			// 'SQL command'
			_sqlCommand = Utils.DataToString(rawData, _currentPos);
			_currentPos = _currentPos + Utils.DataStringLength(rawData, _currentPos);

			// 'Store number of records into'
			_storeNoRecordsInto = Utils.DataToString(rawData, _currentPos);
			_currentPos = _currentPos + Utils.DataStringLength(rawData, _currentPos);

			// 'Database'
			_database = Utils.DataToString(rawData, _currentPos);
			_currentPos = _currentPos + Utils.DataStringLength(rawData, _currentPos);

			ReadParameters();

			Trace.Debug("_sqlCommand = " + _sqlCommand +
				", _storeNoRecordsInto: " + _storeNoRecordsInto +
				", _database = " + _database);

		}
	}
}
